/*
    Wild Flamenco metronome 
    -
    By David Reguera Garcia - Dreg@fr33project.org -
    http://wildflamenco.blogspot.com/

    Copyright (C) <2011>  <David Reguera Garcia>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

*/

#include "container.h"


unsigned int ContainerGetByteIndex( CONTAINER_t * container )
{
    return container->ct * container->unit_size;
}

unsigned int ContainerGetIndex( CONTAINER_t * container )
{
    return container->ct / container->unit_size;
}

void ContainerResetIndex( CONTAINER_t * container )
{
    container->ct = 0;
}

void * ContainerGetElement( CONTAINER_t * container )
{
    return (void *) & ( ( (char *) container->data)[ContainerGetByteIndex(container)] );
}

CONTAINER_t * ContainerInit( CONTAINER_t * container, void * data, unsigned int size, unsigned int unit_size, BOOL copy )
{
    void * alloc_data;

    if ( copy )
    {   
        container->allocated = TRUE;
        alloc_data = calloc( 1, size );
        if ( alloc_data == NULL )
            return NULL;
        else
        {
            memcpy( alloc_data, data, size );
            data = alloc_data;
        }
    }
    else
        container->allocated = FALSE;
    
    container->data = data;
    container->unit_size = unit_size;

    container->ct = 0;
    container->nr_elements = size / unit_size;
    
    return container;
}

unsigned int ContainerGetTotalSize( CONTAINER_t * container )
{
    return container->nr_elements * container->unit_size;
}

BOOL ContainerAddElement( CONTAINER_t * container, void * element )
{
    void * new_data;
    
    new_data = calloc( 1, ContainerGetTotalSize( container ) + container->unit_size );
    if ( new_data == NULL )
        return FALSE;
 
    memcpy( new_data, container->data, ContainerGetTotalSize( container ) );

    memcpy( & ( ((char *) new_data)[ContainerGetTotalSize( container )] ), element, container->unit_size ); 

    if ( container->allocated )
        free( container->data );
    else    
        container->allocated = TRUE;

    container->nr_elements++;
    container->data = new_data;

    return TRUE;
}

BOOL ContainerDelElement( CONTAINER_t * container, void * ptr_to_data )
{
    void * new_data;
    int index;
    
    new_data = calloc( 1, ContainerGetTotalSize( container ) - container->unit_size );
    if ( new_data == NULL )
        return FALSE;

    index = ( (char *) ptr_to_data ) - ( (char *) container->data) ;
    if ( index != 0 )
        memcpy( new_data, container->data, index );
    
    if ( index < ContainerGetTotalSize( container ) - container->unit_size )
        memcpy( & ((char *) new_data)[index], & ( ( (char *) container->data)[index + container->unit_size] ), ContainerGetTotalSize( container ) - container->unit_size  );


    if ( container->allocated )
        free( container->data );
    else    
        container->allocated = TRUE;

    container->nr_elements--;
    container->data = new_data;
    if ( ( container->ct + 1) >= container->nr_elements )
        container->ct--; 

    return TRUE;
}

void ContainerDelete( CONTAINER_t * container )
{
    if ( container->allocated )
        free( container->data );
}

void * ContainerNextElement( CONTAINER_t * container, BOOL * first )
{
    if ( first != NULL )
        * first = FALSE;

    container->ct++;
    if ( container->ct >= container->nr_elements )
    {
        if ( first != NULL )
            * first = TRUE;
        container->ct = 0;
    }

    return ContainerGetElement( container );
}

unsigned int ContainerGetNrElement( CONTAINER_t * container )
{
    return container->nr_elements;
}

/*
int main( void )
{
    int vector[] = { 1, 4, 5 };
    int i;
    CONTAINER_t container;
    BOOL last = 0;

    ContainerInit( & container, vector, sizeof( vector ), sizeof( * vector ), FALSE );

    for ( i = 0; i < 3; i++ )
    {
        printf( " %d\n", * ( (int * )ContainerGetElement( & container ) ) );
        ContainerNextElement( & container, & last );
    }

    
    ContainerNextElement( & container, NULL );
    printf( " Deleting... %d\n", * ( (int * )ContainerGetElement( & container ) ) );
    ContainerDelElement( & container, ContainerGetElement( & container ) );

    ContainerAddElement( & container, & vector[2] );
    

    ContainerDelete( & container );

    getchar();
    return 0;
}
*/

